package handlers

import (
    "errors"
    "$GO_BOOTSTRAP_REPO_NAME/$GO_BOOTSTRAP_REPO_USER/$GO_BOOTSTRAP_PROJECT_NAME/models"
    "$GO_BOOTSTRAP_REPO_NAME/$GO_BOOTSTRAP_REPO_USER/$GO_BOOTSTRAP_PROJECT_NAME/libhttp"
    "github.com/gorilla/sessions"
    "github.com/jmoiron/sqlx"
    "html/template"
    "net/http"
    "strings"
)

func GetSignup(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html")

    tmpl, err := template.ParseFiles("templates/users/users-external.html.tmpl", "templates/users/signup.html.tmpl")
    if err != nil {
        libhttp.HandleErrorJson(w, err)
        return
    }

    tmpl.Execute(w, nil)
}

func PostSignup(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html")

    db := r.Context().Value( "db").(*sqlx.DB)

    email := r.FormValue("Email")
    password := r.FormValue("Password")
    passwordAgain := r.FormValue("PasswordAgain")

    _, err := models.NewUser(db).Signup(nil, email, password, passwordAgain)
    if err != nil {
        libhttp.HandleErrorJson(w, err)
        return
    }

    // Perform login
    PostLogin(w, r)
}

func GetLoginWithoutSession(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html")

    tmpl, err := template.ParseFiles("templates/users/users-external.html.tmpl", "templates/users/login.html.tmpl")
    if err != nil {
        libhttp.HandleErrorJson(w, err)
        return
    }

    tmpl.Execute(w, nil)
}

// GetLogin get login page.
func GetLogin(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html")

    sessionStore := r.Context().Value("sessionStore").(sessions.Store)

    session, _ := sessionStore.Get(r, "$GO_BOOTSTRAP_PROJECT_NAME-session")

    currentUserInterface := session.Values["user"]
    if currentUserInterface != nil {
        http.Redirect(w, r, "/", 302)
        return
    }

    GetLoginWithoutSession(w, r)
}

// PostLogin performs login.
func PostLogin(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html")

    db := r.Context().Value( "db").(*sqlx.DB)
    sessionStore := r.Context().Value( "sessionStore").(sessions.Store)

    email := r.FormValue("Email")
    password := r.FormValue("Password")

    u := models.NewUser(db)

    user, err := u.GetUserByEmailAndPassword(nil, email, password)
    if err != nil {
        libhttp.HandleErrorJson(w, err)
        return
    }

    session, _ := sessionStore.Get(r, "$GO_BOOTSTRAP_PROJECT_NAME-session")
    session.Values["user"] = user

    err = session.Save(r, w)
    if err != nil {
        libhttp.HandleErrorJson(w, err)
        return
    }

    http.Redirect(w, r, "/", 302)
}

func GetLogout(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html")

    sessionStore := r.Context().Value( "sessionStore").(sessions.Store)

    session, _ := sessionStore.Get(r, "$GO_BOOTSTRAP_PROJECT_NAME-session")

    delete(session.Values, "user")
    session.Save(r, w)

    http.Redirect(w, r, "/login", 302)
}

func PostPutDeleteUsersID(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html")

    method := r.FormValue("_method")
    if method == "" || strings.ToLower(method) == "post" || strings.ToLower(method) == "put" {
        PutUsersID(w, r)
    } else if strings.ToLower(method) == "delete" {
        DeleteUsersID(w, r)
    }
}

func PutUsersID(w http.ResponseWriter, r *http.Request) {
    userId, err := getIdFromPath(w, r)
    if err != nil {
        libhttp.HandleErrorJson(w, err)
        return
    }

    db := r.Context().Value( "db").(*sqlx.DB)

    sessionStore := r.Context().Value( "sessionStore").(sessions.Store)

    session, _ := sessionStore.Get(r, "$GO_BOOTSTRAP_PROJECT_NAME-session")

    currentUser := session.Values["user"].(*models.UserRow)

    if currentUser.ID != userId {
        err := errors.New("Modifying other user is not allowed.")
        libhttp.HandleErrorJson(w, err)
        return
    }

    email := r.FormValue("Email")
    password := r.FormValue("Password")
    passwordAgain := r.FormValue("PasswordAgain")

    u := models.NewUser(db)

    currentUser, err = u.UpdateEmailAndPasswordById(nil, currentUser.ID, email, password, passwordAgain)
    if err != nil {
        libhttp.HandleErrorJson(w, err)
        return
    }

    // Update currentUser stored in session.
    session.Values["user"] = currentUser
    err = session.Save(r, w)
    if err != nil {
        libhttp.HandleErrorJson(w, err)
        return
    }

    http.Redirect(w, r, "/", 302)
}

func DeleteUsersID(w http.ResponseWriter, r *http.Request) {
    err := errors.New("DELETE method is not implemented.")
    libhttp.HandleErrorJson(w, err)
    return
}
